package com.googlecode.afdbaccess.web.common.login;

import java.security.acl.Group;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.log4j.Logger;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;

import com.googlecode.afdbaccess.cache.TransactionBase;
import com.googlecode.afdbaccess.cache.exceptions.DataLayerException;
import com.googlecode.afdbaccess.cache.exceptions.DataLayerWrappedSqlException;
import com.googlecode.afdbaccess.cache.preparedstatement.PreparedStatementArgumentsSetterHelper;
import com.googlecode.afdbaccess.cache.resultconversion.exceptions.DataLayerWrappedResultSetConversionException;
import com.googlecode.afdbaccess.cache.resultconversion.exceptions.NoRowsReturnedException;
import com.googlecode.afdbaccess.cache.resultconversion.helpers.ResultSetConverterWithResult;

class UserInfoFetcher extends TransactedTask<Group[]> {
    private final static Logger log = Logger.getLogger(UserInfoFetcher.class);

    private static class Private {
        public static class Converter extends ResultSetConverterWithResult<Group[]> {
            @Override
            public Group[] convertResultSet(ResultSet rs) throws DataLayerException, SQLException {
                if (rs.next()) {
                    String username = rs.getString("identification");
                    long userId = rs.getLong("Person_id");
                    String displayName = rs.getString("displayName");
                    String firstRole = rs.getString("role");
                    
                    // Groups
                    SimpleGroup groups = new SimpleGroup("Roles");
                    
                    if(firstRole != null) {
                        addRole(groups, firstRole);
                        
                        while(rs.next()) {
                            String role = rs.getString("role");
                            addRole(groups, role);
                        }
                    }
                    
                    // Main info
                    SimpleGroup callerPrincipal = new SimpleGroup("CallerPrincipal"); 
                    callerPrincipal.addMember(new ApplicationPrincipal(username, userId, displayName));
            
                    // Compose end result
                    Group[] returnObject = {
                        groups,
                        callerPrincipal
                    };
                    
                    // Done
                    return returnObject;
                } else {
                    throw new NoRowsReturnedException("User could not be found in database.");
                }
            }

            private void addRole(SimpleGroup groups, String roleString) {
                log.debug("Adding role to principal: " + roleString);
                SimplePrincipal role = new SimplePrincipal(roleString);
                groups.addMember(role);
            }
        }
    }
    
    @Override
    protected Group[] perform(TransactionBase t, String username) throws DataLayerWrappedSqlException, DataLayerWrappedResultSetConversionException, DataLayerException {
        String sql = "";
        sql += "SELECT\n";
        sql += "  PersonIdentification.identification,\n";
        sql += "  Person.Person_id,\n";
        sql += "  Person.displayName,\n";
        sql += "  PersonRoleType.constantId role\n";
        sql += "FROM\n";
        sql += "  Person,\n";
        sql += "  PersonIdentification,\n";
        sql += "  PersonIdentificationType,\n";
        sql += "  PersonRole,\n";
        sql += "  PersonRoleType\n";
        sql += "WHERE\n";
        sql += "  PersonIdentification.identification = ? AND\n";
        sql += "  PersonIdentification.Person_id = Person.Person_id AND\n";
        sql += "  PersonIdentification.PersonIdentificationType_id = PersonIdentificationType.PersonIdentificationType_id AND\n";
        sql += "  PersonIdentificationType.constantId = 'username' AND\n";
        sql += "  Person.Person_id = PersonRole.Person_id AND\n";
        sql += "  PersonRole.PersonRoleType_id = PersonRoleType.PersonRoleType_id\n";

        PreparedStatementArgumentsSetterHelper setter = new PreparedStatementArgumentsSetterHelper();
        setter.addArgument(username.toLowerCase());
        
        return t.executeQuery(sql, setter, Private.Converter.class, 0);
    }
}
